/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.common.base.service;

import com.je.common.auth.impl.account.Account;
import com.je.common.base.DynaBean;
import com.je.common.base.constants.ConstantVars;
import com.je.common.base.constants.tree.NodeType;
import com.je.common.base.db.JEDatabase;
import com.je.common.base.entity.QueryInfo;
import com.je.common.base.entity.func.FuncInfo;
import com.je.common.base.mapper.query.Query;
import com.je.common.base.mvc.BaseMethodArgument;
import com.je.common.base.util.SecurityUserHolder;
import com.je.common.base.util.StringUtil;
import com.je.core.entity.extjs.JSONTreeNode;
import com.je.ibatis.extension.conditions.ConditionsWrapper;

import javax.servlet.http.HttpServletRequest;
import java.sql.Clob;
import java.util.*;

/**
 * 通用业务方法
 *
 * @author wangmm@ketr.com.cn
 * @date 2019/12/6
 */
public interface CommonService {

    /**
     * 检查功能是否是多根树
     *
     * @param funcCode
     * @return
     */
    boolean checkFuncMoreRoot(String funcCode);

    /**
     * 查找子功能外键
     *
     * @param funcCode
     * @return
     */
    String findSubFuncForeignField(String funcCode);

    /**
     * 添加多根树根节点
     *
     * @param funcCode
     * @param dynaBean
     */
    DynaBean addFuncMoreRootNode(String funcCode, DynaBean dynaBean);

    DynaBean addFuncMoreRootNode(String funcCode, DynaBean dynaBean, String subFuncForeignKey);


    /**
     * 构建排序
     *
     * @param dynaBean
     */
    void generateOrderIndex(DynaBean dynaBean, String wheresql);

    /**
     * 加载dynaBean的动态表格树
     *
     * @param rootId    根节点ID
     * @param tableCode 表名
     * @param excludes
     * @param checked   是否选中
     * @param queryInfo 查询对象
     * @return
     * @ excludes 排除树形  按逗号隔开  一般排除的是checked 去掉得树节点前无多选框
     */
    List<Map<String, Object>> loadTree(String rootId, String tableCode, String excludes, Boolean checked, QueryInfo queryInfo);

    /**
     * 加载dyanBean树形数据
     *
     * @param rootId
     * @param template
     * @param dynaBean
     * @return
     */
    List<Map<String, Object>> loadTree(String rootId, JSONTreeNode template, DynaBean dynaBean, QueryInfo queryInfo);

    /**
     * 加载表格树
     *
     * @param rootId
     * @param template
     * @param table
     * @return
     */
    List<Map<String, Object>> loadTree(String rootId, JSONTreeNode template, DynaBean table, String excludes, Boolean checked, QueryInfo queryInfo);

    /**
     * 构建DynaBean指定功能上的默认值
     *
     * @param funcCode
     * @param dynaBean
     * @return
     */
    void buildFuncDefaultValues(String funcCode, DynaBean dynaBean);

    /**
     * 构建排序条件
     *
     * @param sort
     * @param orderSql    排序sql
     * @param useOrderSql TODO 暂不明确
     * @return
     */
    String buildOrderSql(String sort, String orderSql, String useOrderSql);

    /**
     * 构建ExtJs点击列按指定列排序
     *
     * @param sort     TODO 暂不明确
     * @param excludes TODO 暂不明确
     * @return
     */
    String buildSortOrder(String sort, String excludes);

    /**
     * 构建创建信息
     *
     * @param model 业务bean
     */
    void buildResourceTable(DynaBean model);

    /**
     * 构建创建信息
     *
     * @param model 业务bean
     */
    default void buildModelCreateInfo(DynaBean model) {
        buildModelCreateInfo(model, SecurityUserHolder.getCurrentAccount());
    }

    /**
     * 前端使用列表批量添加时设置一个虚拟字段，用于存储前端传递的主键
     * 后端会把前端传递的主键放到一个虚拟字段中，用于前端回显赋值使用
     * <p>
     * 将bean中的pkValue制空，mybatis允许用户传递主键，但是前端自动生成的需要清理
     *
     * @param model 业务bean
     */
    String getModelCreateListInsertId(DynaBean model);

    /**
     * 构建创建信息
     *
     * @param model          业务bean
     * @param currentAccount 用户
     */
    void buildModelCreateInfo(DynaBean model, Account currentAccount);

    /**
     * 构建修改信息
     *
     * @param model 业务bean
     */
    default void buildModelModifyInfo(DynaBean model) {
        buildModelModifyInfo(model, SecurityUserHolder.getCurrentAccount());
    }

    /**
     * 构建修改信息
     *
     * @param model          业务bean
     * @param currentAccount 用户
     */
    void buildModelModifyInfo(DynaBean model, Account currentAccount);

    /**
     * 自动生成字段赋值
     *
     * @param fieldCode 系统自动生成字段的code
     * @param funcCode  功能code
     * @param dynaBean  实体
     * @return 生成的值
     */
    default String buildCode(String fieldCode, String funcCode, DynaBean dynaBean) {
        return buildCode(fieldCode, funcCode, dynaBean, "");
    }

    /**
     * 自动生成字段赋值
     *
     * @param fieldCode 系统自动生成字段的code
     * @param funcCode  功能code
     * @param dynaBean  实体
     * @param zhId      租户ID
     * @return 生成的值
     */
    String buildCode(String fieldCode, String funcCode, DynaBean dynaBean, String zhId);

    /**
     * 自动生成字段赋值
     *
     * @param codeGenFieldInfo 自动生成编号配置
     * @param dynaBean         实体
     */
    default void buildCode(String codeGenFieldInfo, DynaBean dynaBean) {
        buildCode(codeGenFieldInfo, dynaBean, "");
    }

    /**
     * 自动生成字段赋值
     *
     * @param codeGenFieldInfo 自动生成编号配置
     * @param dynaBean         实体
     * @param zhId             租户ID
     */
    void buildCode(String codeGenFieldInfo, DynaBean dynaBean, String zhId);

    /**
     * 保存业务bean
     *
     * @param dynaBean 业务bean
     * @return com.je.core.util.bean.DynaBean
     */
    DynaBean doSave(DynaBean dynaBean);

    /**
     * 构建树形的排序序号
     *
     * @param dynaBean 业务bean
     */
    void generateTreeOrderIndex(DynaBean dynaBean);

    /**
     * 文件保存业务元数据信息
     *
     * @param dynaBean         业务bean
     * @param batchFilesFields 多附件字段名
     * @param uploadableFields 单附件字段名
     * @param funcCode         功能编码
     */
    void doSaveFileMetadata(DynaBean dynaBean, String batchFilesFields, String uploadableFields, String funcCode);

    /**
     * 视图类型功能处理
     *
     * @param funcCode 功能编码
     * @param dynaBean 业务bean
     */
    DynaBean doViewData(String funcCode, DynaBean dynaBean);

    /**
     * 视图类型功能处理
     *
     * @param funcCode 功能编码
     * @param dynaBean 业务bean
     */
    DynaBean doViewData(String funcCode, DynaBean dynaBean, DynaBean funcInfo);


    /**
     * 子功能默认添加树形ROOT节点操作
     *
     * @param dynaBean 业务bean
     * @param funcCode 功能编码
     */
    void doChildrenTree(DynaBean dynaBean, String funcCode);

    /**
     * 递归复制子功能数据
     *
     * @param dynaBean         被复制数据
     * @param funcCode         功能code
     * @param codeGenFieldInfo 构建编号字段
     * @param uploadableFields 附件字段
     * @return com.je.core.util.bean.DynaBean
     */
    DynaBean doCopy(DynaBean dynaBean, String funcCode, String codeGenFieldInfo, String uploadableFields);

    /**
     * 删除子功能数据
     *
     * @param funcCode  功能code
     * @param tableCode 表名
     * @param pkCode    主键字段名
     * @param ids       被删除数据ID
     * @param doTree    是否是树形
     */
    void removeChild(String funcCode, String tableCode, String pkCode, String ids, boolean doTree);

    /**
     * 删除批量附件处理
     *
     * @param tableCode 表code
     * @param ids       被删除数据ID
     */
    void doRemoveBatchFiles(String tableCode, String ids);

    /**
     * 删除树形批量附件处理
     *
     * @param tableCode 表code
     * @param ids       被删除数据ID
     */
    void doRemoveTreeBatchFiles(String tableCode, String ids);

    /**
     * 根据视图级联配置删除数据
     *
     * @param viewConfigInfo 视图级联配置
     * @param viewTableCode  视图名称
     * @param mainPkCode     主键字段名
     * @param ids            被删除数据ID
     */
    int doViewDelData(String viewConfigInfo, String viewTableCode, String mainPkCode, String ids);

    /**
     * doUpdateList
     *
     * @param tableCode        表名
     * @param updateStr        数据
     * @param funcType         功能类型
     * @param funcCode         功能编码
     * @param codeGenFieldInfo 自动生成编号字段
     * @return java.util.List<com.je.core.util.bean.DynaBean>
     */
    List<DynaBean> doUpdateList(String tableCode, String updateStr, String funcType, String funcCode, String codeGenFieldInfo);

    /**
     * doUpdateListByJquery
     *
     * @param tableCode 表名
     * @param funcType  功能类型
     * @param funcCode  功能编码
     * @param values    是否全部修改  0 是 1 不是
     * @return java.util.List<com.je.core.util.bean.DynaBean>
     */
    @Deprecated
    int doUpdateAllList(String tableCode, String funcType, String funcCode, Map<String, Object> values, BaseMethodArgument param, HttpServletRequest request);

    /**
     * doUpdateList
     *
     * @param tableCode      表名
     * @param updateStr      数据
     * @param funcType       功能类型
     * @param viewConfigInfo 视图级联配置
     * @return java.util.List<com.je.core.util.bean.DynaBean>
     */
    List<DynaBean> doUpdateList(String tableCode, String updateStr, String funcType, String viewConfigInfo);

    /**
     * updateTreePanent4NodeType
     *
     * @param tableCode 实体
     * @param parentId  父级id
     * @return void
     */
    void updateTreePanent4NodeType(String tableCode, String parentId);

    /**
     * 验证字段唯一
     *
     * @param dynaBean  实体
     * @param fieldCode 验证字段
     * @return Boolean
     */
    default Boolean checkFieldUnique(DynaBean dynaBean, String fieldCode) {
        return checkFieldUnique(dynaBean, fieldCode, new Query());
    }

    /**
     * 验证字段唯一
     *
     * @param dynaBean  实体
     * @param fieldCode 验证字段
     * @param query     附加条件
     * @return Boolean
     */
    Boolean checkFieldUnique(DynaBean dynaBean, String fieldCode, Query query);

    /**
     * loadTree
     *
     * @param rootId    根节点ID
     * @param tableCode 资源表名
     * @param excludes
     * @param checked
     * @param query     查询条件
     * @return java.util.List
     */
    List<Map<String, Object>> loadGridTree(String rootId, String tableCode, String excludes, Boolean checked, Query query);

    default List<JSONTreeNode> buildJsonTreeNodeList(JSONTreeNode template, List<Map<String, Object>> treeItemList, List<String> includeIds, String[] beanFields, boolean async) {
        List<JSONTreeNode> list = new ArrayList<>();
        //遍历结果构建树形节点对象
        treeItemList.forEach(record -> {

            //主键
            String nodeId = (String) record.get(template.getId());
            //排除不在指定节点内的数据
            if (includeIds != null && includeIds.size() > 0 && !includeIds.contains(nodeId)) {
                return;
            }
            JSONTreeNode node = new JSONTreeNode();
            node.setAsync(async);

            node.setId(nodeId);

            node.setText((String) record.get(template.getText()));
            //编码
            node.setCode((String) record.get(template.getCode()));
            //父节点
            node.setParent((String) record.get(template.getParent()));
            //节点信息
            if (StringUtil.isNotEmpty(template.getNodeInfo())) {
                node.setNodeInfo(StringUtil.getClobValue(record.get(template.getNodeInfo())));
            }
            //节点信息类型
            if (StringUtil.isNotEmpty(template.getNodeInfoType())) {
                node.setNodeInfoType(record.get(template.getNodeInfoType()) + "");
            }
            //是否叶子
            if (StringUtil.isNotEmpty(template.getNodeType())) {
                node.setLeaf(NodeType.LEAF.equalsIgnoreCase(record.get(template.getNodeType()) + ""));
                node.setNodeType(record.get(template.getNodeType()) + "");
            }
            if (StringUtil.isNotEmpty(template.getLayer())) {
                node.setLayer(record.get(template.getLayer()) + "");
            }
            //图标图片地址
            if (StringUtil.isNotEmpty(template.getIcon())) {
                node.setIcon(record.get(template.getIcon()) + "");
            }
            //图标样式
            if (StringUtil.isNotEmpty(template.getIconColor())) {
                node.setIconColor(record.get(template.getIconColor()) + "");
            }
            //是否禁用
            if (StringUtil.isNotEmpty(template.getDisabled())) {
                node.setDisabled(record.get(template.getDisabled()) + "");
            } else {
                node.setDisabled("0");
            }
            //树形路径
            if (StringUtil.isNotEmpty(template.getNodePath())) {
                node.setNodePath(record.get(template.getNodePath()) + "");
            }
            //描述
            if (StringUtil.isNotEmpty(template.getDescription())) {
                node.setDescription(StringUtil.getClobValue(record.get(template.getDescription())));
            }
            //排序
            if (StringUtil.isNotEmpty(template.getOrderIndex())) {
                node.setOrderIndex(record.get(template.getOrderIndex()) + "");
            }
            if (StringUtil.isNotEmpty(template.getTreeOrderIndex())) {
                node.setTreeOrderIndex(record.get(template.getTreeOrderIndex()) + "");
            }

            //保留指定字段
            if (beanFields != null && beanFields.length > 0) {
                List<String> fieldList = Arrays.asList(beanFields);
                Set<String> keySet = record.keySet();
                for (String key : keySet) {
                    if (!fieldList.contains(key)) {
                        record.remove(key);
                    }
                    ;
                }

            }
            //如果是oracle则单独处理
            if (ConstantVars.STR_ORACLE.equals(JEDatabase.getCurrentDatabase())) {
                record.forEach((key, val) -> {
                    if (val == null) {
                        record.put(key, "");
                    } else if (val instanceof Clob) {
                        record.put(key, StringUtil.getClobValue(record.get(key)));
                    }
                });
            }
            node.setBean(record);
            list.add(node);
        });
        return list;
    }

    default List<JSONTreeNode> loadTreeNodeList(String rootId, String tableName, JSONTreeNode template, Query where) {
        return loadTreeNodeList(rootId, tableName, template, where, null, null);
    }

    List<JSONTreeNode> loadTreeNodeList(String rootId, String tableName, JSONTreeNode template, Query where, List<String> includeIds, String[] beanFields);

    JSONTreeNode buildJSONNewTree(List<JSONTreeNode> lists, String rootId);

    /**
     * 功能配置
     *
     * @param funcCode 功能code
     * @return com.je.develop.vo.FuncInfo
     */
    FuncInfo functionConfig(String funcCode);

    /**
     * 更改默认方案
     *
     * @param dynaBean
     * @param key1
     * @param key2
     * @return
     */
    DynaBean changeDefaultPlan(DynaBean dynaBean, String key1, String key2);

    List<JSONTreeNode> getLocalJsonTreeNodeList(String rootId, String tableName, JSONTreeNode template, QueryInfo queryInfo);

    List<JSONTreeNode> getLocalJsonTreeNodeList(String rootId, String tableName, JSONTreeNode template, QueryInfo queryInfo, List<String> includeIds, String[] beanFields);

    /**
     * 构建产品查询
     *
     * @param jquery
     */
    void buildProductQuery(Query jquery, String column);

    /**
     * 构建产品查询
     *
     * @param jquery
     */
    void buildProductQuery(Query jquery);

    /**
     * 构建产品查询
     *
     * @param wrapper
     */
    void buildProductWrapper(ConditionsWrapper wrapper);

    /**
     * 构建产品查询
     *
     * @param wrapper
     */
    void buildProductWrapper(ConditionsWrapper wrapper, String column);

    /**
     * 校验bean更新权限
     *
     * @param funcCode
     * @param tableCode
     * @param pkCode
     * @param pkValue
     * @return
     */
    boolean validDynaBeanUpdatePerm(String funcCode, String tableCode, String pkCode, String pkValue);

    /**
     * 校验bean list更新权限
     *
     * @param funcCode
     * @param tableCode
     * @param wrapper
     * @return
     */
    boolean validDynaBeanListUpdatePerm(String funcCode, String tableCode, ConditionsWrapper wrapper);

    /**
     * 校验bean删除全新
     *
     * @param funcCode
     * @param tableCode
     * @param pkCode
     * @param pkValue
     * @return
     */
    boolean validDynaBeanDeletePerm(String funcCode, String tableCode, String pkCode, String pkValue);

    /**
     * 校验bean list 删除全新
     *
     * @param funcCode
     * @param tableCode
     * @param wrapper
     * @return
     */
    boolean validDynaBeanListDeletePerm(String funcCode, String tableCode, ConditionsWrapper wrapper);

    /**
     *
     */
    void buildProductInfo(DynaBean dynaBean);

    /**
     * @param asList
     * @param userId
     */
    void deleteByFileKeys(List<String> asList, String userId);

    /**
     * 根据id，修改字典项name值，比如 id=1,2,3 name="JE,PASS,TEMP" ,传入id=2,name=CLOUD，可以修改成“JE,CLOUD,TEMP”
     *
     * @param id
     * @param name
     */
    void updateDictionaryItemNameById(String id, String name, String tableCode, String nameCode, String idCode, String pkCode);

}
